In the evolution of computers, two systems were developed for handling the interaction between the computer and peripheral devices such as printers, plotters, disk drives, and the like.
The first such system is known in the art as an "interrupt" driven system. Parallel printers typically have employed an interrupt driven port device driver for handling the printer and parallel port which, for reasons which will be hereinafter set forth, often resulted in unnecessarily high CPU usage and poor system response.
Although the advances provided by the subject invention are most easily understood with respect to the conventional example of printers operating on such a parallel port, the invention is not intended to be so limited and admits to application to I/O problems associated with other devices and other ports such as serial ports.
In accordance with the conventional operation of such an interrupt-driven printer device driver, a byte of data is strobed to the printer, whereupon the printer typically responds by pulsing an acknowledgement or "ack" line, thereby generating an "interrupt" serviced by the corresponding CPU interrupt routine. The device driver interrupt routine thereafter strobes out a next byte of data for the printer, and the cycle continues.
In the earlier days of computing, such parallel printers were provided which worked quite well in relatively simple systems such as those employing 8 bit CPUs at relatively low nominal clock rates of 4 megahertz. These printers were designed to be interrupt driven so that each character to be printed presented the CPU with an interrupt. The CPU would fetch a byte from memory corresponding to a character for each interrupt for delivery to the printer, whereupon it was subsequently printed. Such interrupt-driven printers, which were relatively slow and unintelligent, were for the most part found acceptable even though they exhibited relatively low data throughput. In part this acceptance was due to the aforementioned relative simplicity of the CPU itself and the resulting slow performance of its other tasks.
One problem however with this approach of interrupt driven systems is that asynchronous hardware interrupts are relatively "expensive" in terms of CPU usage. In order to respond to an interrupt in a timely manner, the CPU's operating system must immediately save the current machine state, execute the appropriate interrupt handler, and then restore the machine state.
In simplistic terms this meant that upon occurrence of an interrupt the computer system must cease its current process (such as tracing a diagram), enter the interrupt service routine, perform whatever process was necessary to handle the routine (e.g. writing a byte to the printer, etc.), as well as storing and restoring the state variables of the machine environment so that the process which was interrupted could be restarted at the appropriate place. Such state variables would include, of course, the numerous CPU registers and stack. Thus it may be appreciated that when the CPU was thereby required to interrupt performance of its system functions and duties to handle an interrupt from a parallel port, instances would arise when this became a problem in terms of unduly loading the system.
As previously noted, the earlier systems were reasonably tolerable wherein the system CPU handled simple data transfer to peripheral devices (such as one byte ASCII characters) without hardware assist provided by printer coprocessors or the like--this, notwithstanding that the CPU was transferring data a byte at a time. However, eventually this problem of slow data rates and processor loading due to interrupts became noticeable enough as to actually become unacceptable.
A very practical example of how this problem of loading the CPU with interrupts manifested itself and been exacerbated relates to the evolution in complexity of peripheral devices themselves. For example, as printers became more powerful (such as those compatible with the postscript language and providing sophisticated graphics), the need for greater throughput to the printer rose significantly in order to fully utilize its potential. This capacity for increased throughput was in part due to dedicated processors and buffers being provided in the printer itself. It is not uncommon today to encounter printers which may accept 50,000 characters or more per second handling huge postscript graphics files on the order of 10 megabytes or more which must be dumped from the CPU to the printer at these immense data rates. It will thus be appreciated that the CPU having to handle in excess of 50,000 interrupts per second for a peripheral device severely impacts its ability to perform other necessary functions.
One of the fundamental problems with such interrupt-driven systems is that whenever an event occurs (such as desired printing of the character) an interrupt is generated conveying to the CPU such desire. However, the peripheral device, such as a printer in this case, may nevertheless be incapable of printing a character at the time of the interrupt for various reasons (out of paper, line or sheet feed, malfunction, or the like). Nevertheless, the CPU invokes the interrupt handler and processes the interrupt even if the net result thereof is an inability to carry out the task prompting the interrupt in the first place. It may readily be appreciated that as the rate of these interrupts increased, this would often result in a substantial amount of the bandwidth of the CPU being needlessly wasted processing these interrupts which resulted in no action due to the particular state of the peripheral device].
The other basic system for handling the interaction between computers and peripheral devices is known in the art as a "polled" system. In such a polled system, a peripheral device was polled periodically at intervals to check its state and receptiveness to data throughput from the CPU. While this seemed to work in certain systems, there was nevertheless a fundamental problem which may be illustrated again utilizing the printer example. Many peripheral devices have widely varying delay characteristics dependent upon the particular function being executed at a given time. For example, one may appreciate the difference in delay associated with even modern laser printer handling very simple ASCII text on the one hand, or the aforementioned highly complex graphics tasks such as those associated with a postscript file. These delay characteristics of peripherals will vary widely dependent on numerous factors such as, in the case of a printer, the particular print engine, inasmuch as there is even a dedicated processor in some such printers. Throughput might be relatively rapid for graphics files wherein the printer itself has very little processing to do. However, a postscript file might result in such a printer being busy a proportionately higher amount of time because the dedicated processor therein must interpret the postscript data with the printer. From the foregoing, it should be apparent that whereas a polled system might avoid some of the problems associated with the previously described interrupt system (wherein interrupts unnecessarily tie up the CPU), the polling system itself has difficulty in handling peripheral devices with such widely varying timing requirements.
This problem with polled systems gave rise to efforts to attempt to tune such polled systems to provide an optimum balance between system load and data throughput. An illustrative example of such an approach may be found in U.S. Pat. No. 5,081,577 to Hatle. This system sought to optimize a representative fixed delay between polls which was judiciously selected based upon the characteristics of the particular peripheral device. The polling interval was optimized so as to not be too frequent (such that it would occur too often when the peripheral device was busy) and yet not too infrequent (whereby the throughput was adversely affected because the peripheral device was idle awaiting a poll).
Whereas this approach appeared to afford advantages over interrupt driven systems, it nevertheless became readily apparent that an inherent weakness of the system was that it was extremely inflexible. Each peripheral device has differing delay characteristics depending upon its particular functions. When a peripheral device in accordance with the Hatle system was changed, the optimized polling interval might be completely inappropriate, thereby resulting in the need to re-optimize. There was no provision for user-settable polling parameters. Even if this were possible, it would presume a level of knowledge about the peripheral device in the user which, as a practical matter, is unrealistic. Thus, the assumption was that either the provider of a device driver knew the device well enough to provide an appropriate polling period or a system such as that of Hatle could be provided to optimize on the polling period.
However, as we have just seen in the case of a laser printer, many peripheral devices have widely varying delay characteristics. Thus, a fixed polling interval is inappropriate when different peripheral devices are attached to the system. Even as to a particular peripheral device, attempting to optimize the fixed polling period in the manner of Hatle, often resulted in unacceptable system loads on the CPU and/or low data throughput to the peripheral device.
For all the foregoing reasons, an improvement was needed for systems in which hardware is attempting to pass data through to a peripheral device at improved rates and wherein the system is taking up too much CPU time in the interrupt or polling processes.
Moreover, such a system was needed which was applicable to a plurality of different peripheral devices each having its own range of delay characteristics, wherein a better tradeoff was could be between system loading and data throughput than is afforded with conventional systems such as those employing optimized regular polling intervals in the manner of Hatle.
Accordingly it was further an object of the invention to provide for a dynamically changing delay whereby when a printer for example is operating rapidly, throughput delays are minimized and the system will keep up in sync with the printer whereas, if the printer buffer fills up, the polling delay is thereby adapted so that the system is not polled as hard, leaving it free to perform other functions.
In short, it was desirable to provide a system for use with peripheral devices which could exhibit lower system loading as well as improved data throughput.